home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1998…tember: Reference Library / Dev.CD Sep 98 RL1.toast / Technical Documentation / develop / develop Issue 24 / develop Issue 24 code / Scriptable Database 1.0a15.sea / Scriptable Database 1.0a15 / Application / ScriptableDBDocument.cp / ScriptableDBDocument.cp
Encoding:
Text File  |  1996-02-20  |  11.9 KB  |  364 lines  |  [TEXT/CWIE]

  1.  
  2. #include "ScriptableDBDocument.h"
  3.  
  4. #include "HFSBackingStore.h"
  5. #include "DBElementToken.h"
  6. #include "Application.h"
  7.  
  8. #include "DBRecord.h"
  9. #include "DBElement.h"
  10. #include "DBProperty.h"
  11. #include "DataRecord.h"
  12.  
  13. #include "Exceptions.h"
  14.  
  15. #include <AppleEvents.h>
  16. #include <AERegistry.h>
  17. #include <ASRegistry.h>
  18.  
  19. TScriptableDBDocument* gScriptableDocumentList = nil;
  20.  
  21. TPropertyDescription TScriptableDBDocument::fPropertiesOfClass[] = {
  22.     {    pIsModified,            0,        typeBoolean,                typeBoolean                }
  23. };
  24.  
  25. #pragma segment ObjectResident
  26. ImplementClassData(TScriptableDBDocument, clScriptableDBDocument);
  27.  
  28. //--------------------------------------------------------------------------------
  29. // TScriptableDBDocument::~TScriptableDBDocument
  30. //--------------------------------------------------------------------------------
  31. TScriptableDBDocument::~TScriptableDBDocument()
  32. {
  33.     //
  34.     // Save changes before going away.  Generally speaking, it's bad
  35.     // to do things like this in the destructor.  It's far better to
  36.     // have a Dispose() method that calls all of the methods such as
  37.     // 'save' that may need to be called, and then does a 'delete this'.
  38.     // That way, derived classes can override methods called from the
  39.     // destructor and they will still be called.
  40.     //
  41.     this->Save();
  42. }
  43.  
  44. //--------------------------------------------------------------------------------
  45. // TScriptableDBDocument::NewDatabase
  46. //--------------------------------------------------------------------------------
  47. TScriptableDBDocument* TScriptableDBDocument::NewDatabase()
  48. {
  49.     TScriptableDBDocument* newDatabase = new TScriptableDBDocument();
  50.     
  51.     return newDatabase;
  52. }
  53.  
  54. //--------------------------------------------------------------------------------
  55. // TScriptableDBDocument::OpenDatabase
  56. //--------------------------------------------------------------------------------
  57. TScriptableDBDocument* TScriptableDBDocument::OpenDatabase(TFSSpecification& fileSpec)
  58. {
  59.     THFSBackingStore* backingStore = new THFSBackingStore(fileSpec);
  60.     TScriptableDBDocument* openDatabase = new TScriptableDBDocument(backingStore);
  61.     
  62.     return openDatabase;
  63. }
  64.  
  65. //--------------------------------------------------------------------------------
  66. // TScriptableDBDocument::OpenDatabase
  67. //--------------------------------------------------------------------------------
  68. TScriptableDBDocument* TScriptableDBDocument::OpenDatabase(TFSSpecification& fileSpec, Int64 requiredDocumentID)
  69. {
  70.     TScriptableDBDocument* foundDatabase = nil;
  71.     
  72.     //
  73.     // First, test to see if the database is already open.
  74.     // If so, we don't want to open it again.
  75.     //
  76.     TAbstractDocument* openDatabase = TApplication::Instance()->FindDocument(fileSpec);
  77.     if(openDatabase != nil)
  78.     {
  79.         //
  80.         // Only downcast if the document type is correct
  81.         //
  82.         if((openDatabase->DerivedFrom(clScriptableDBDocument)) && (openDatabase->DocumentIdentifier() == requiredDocumentID))
  83.             foundDatabase = (TScriptableDBDocument*)openDatabase;
  84.     }
  85.     //
  86.     // If the database wasn't open, then open it and check to
  87.     // see if its document ID matches.
  88.     //
  89.     else
  90.     {
  91.         foundDatabase = TScriptableDBDocument::OpenDatabase(fileSpec);
  92.         if(foundDatabase != nil)
  93.         {
  94.             //
  95.             // If we don't really want to open this database
  96.             // (we're searching for a database with a different
  97.             // document ID), then close and delete it
  98.             //
  99.             if(foundDatabase->DocumentIdentifier() != requiredDocumentID)
  100.             {
  101.                 delete foundDatabase;
  102.                 foundDatabase = nil;
  103.             }
  104.         }
  105.     }
  106.     
  107.     return foundDatabase;
  108. }
  109.  
  110. //::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
  111. // Overrides of class TDatabaseDocument
  112. //::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
  113.  
  114. //--------------------------------------------------------------------------------
  115. // TScriptableDBDocument::DocumentIdentifier
  116. //--------------------------------------------------------------------------------
  117. Int64 TScriptableDBDocument::DocumentIdentifier() const
  118. {
  119.     return TDatabaseDocument::ObjectsKeySpace();
  120. }
  121.  
  122. //::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
  123. // Overrides of class TAbstractDocument
  124. //::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
  125.  
  126. //----------------------------------------------------------------------------------------
  127. // TScriptableDBDocument::DocumentFSSpecification
  128. //
  129. // Return the FSSpec for the file this document is saved in, if any.
  130. //----------------------------------------------------------------------------------------
  131. Boolean TScriptableDBDocument::DocumentFSSpecification(TFSSpecification& fileSpec) const
  132. {
  133.     TAbstractBackingStore* backingStore = this->GetBackingStore();
  134.     Boolean hasFSSpec = false;
  135.     
  136.     if((backingStore != nil) && (backingStore->BackingStoreType() == kHFSBackingStore))
  137.     {
  138.         fileSpec = ((THFSBackingStore*)backingStore)->FileSpec();
  139.         hasFSSpec = true;
  140.     }
  141.     
  142.     return hasFSSpec;
  143. }
  144.  
  145. //::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
  146. // Overrides of class TAbstractScriptableObject
  147. //::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
  148.  
  149. //--------------------------------------------------------------------------------
  150. // TScriptableDBDocument::GetProperty
  151. //--------------------------------------------------------------------------------
  152. TDescriptor TScriptableDBDocument::GetProperty(const TAETransaction& t, DescType propertyName, DescType desiredType, unsigned long additionalInfo /*= 0*/)
  153. {
  154.     TDescriptor result;
  155.     
  156.     switch(propertyName)
  157.     {
  158.         case pName:
  159.         {
  160.             //
  161.             // This fixed-length storage isn't too desirable.
  162.             // We should call DocumentName with a tiny TUpdateDataReference
  163.             // just to find out how long the name is, then preallocate
  164.             // a handle to copy the whole data into.
  165.             //
  166.             // This method is good enough, though, because we know
  167.             // that filenames are never anywhere close to 255 characters long.
  168.             //
  169.             char nameStorage[256];
  170.             TUpdataDataReference name(typeChar, nameStorage, 0, 256);
  171.             this->DocumentName(name);
  172.             result.SetDescriptorData(name);
  173.             break;
  174.         }
  175.  
  176.         case pID:
  177.         {
  178.             result.SetSInt64Data(this->DocumentIdentifier());
  179.             break;
  180.         }
  181.         
  182.         case pIndex:
  183.         {
  184.             result.SetSInt32Data(TApplication::Instance()->DocumentIndex(this->DocumentIdentifier()));
  185.             break;
  186.         }
  187.                 
  188.         case pIsModified:
  189.         {
  190.             result.SetBooleanData(this->DocumentNeedsSave());
  191.             break;
  192.         }
  193.         
  194.         default:
  195.         {
  196.             result = Inherited::GetProperty(t, propertyName, desiredType, additionalInfo);
  197.             break;
  198.         }
  199.     }
  200.         
  201.     return result;
  202. }
  203.  
  204. //--------------------------------------------------------------------------------
  205. // TScriptableDBDocument::SetProperty
  206. //--------------------------------------------------------------------------------
  207. void TScriptableDBDocument::SetProperty(const TAETransaction& t, DescType propertyName, TDescriptor& data, unsigned long additionalInfo /*= 0*/)
  208. {
  209.     Inherited::SetProperty(t, propertyName, data, additionalInfo);
  210. }
  211.  
  212. //--------------------------------------------------------------------------------
  213. // TScriptableDBDocument::MakeKeyDataForSelf
  214. //--------------------------------------------------------------------------------
  215. void TScriptableDBDocument::MakeKeyDataForSelf(const TAETransaction& t, DescType& keyForm, TDescriptor& keyData)
  216. {
  217.     //
  218.     // If this document can be saved, then it has a name.
  219.     //
  220.     if(this->CanSaveDocument())
  221.     {
  222.         Inherited::MakeKeyDataForSelf(t, keyForm, keyData);
  223.     }
  224.     //
  225.     // If we don't have a name, then use our ID
  226.     //
  227.     else
  228.     {
  229.         keyForm = formUniqueID;
  230.         keyData = this->GetProperty(t, pID, typeWildCard, 0); // •••
  231.     }
  232. }
  233.  
  234. //--------------------------------------------------------------------------------
  235. // TScriptableDBDocument::AECommand
  236. //--------------------------------------------------------------------------------
  237. TDescriptor TScriptableDBDocument::AECommand(const TAETransaction& t, long aeCommandID, TAbstractScriptableObject* auxObjects /*= nil*/, long auxInfo /*= 0*/)
  238. {
  239.     TDescriptor result;
  240.     
  241.     switch(aeCommandID)
  242.     {
  243.         case kAESave:
  244.         {
  245.             //
  246.             // If the event specified a "save in" parameter, then
  247.             // do a save-as.  Otherwise, just save.
  248.             //
  249.             TDescriptor saveInFile = t.Message().GetOptionalParameter(keyAEFile);
  250.             if(saveInFile.IsNullDescriptor() == true)
  251.             {
  252.                 //
  253.                 // ••• n.b. Currently, 'save' will silently fail
  254.                 // if no file has been specified.  We can test for
  255.                 // this situation by calling this->CanSaveDocument.
  256.                 // Should we fail, or make an arbitrary file in 
  257.                 // the temp items folder, or...
  258.                 //
  259.                 this->Save();
  260.             }
  261.             else
  262.             {
  263.                 //
  264.                 // Make sure that the file is created when it
  265.                 // is converted from a TDescriptor to a TFSSpecification
  266.                 // 
  267.                 TFSSpecification saveInFSSpec(saveInFile, kForceFileCreation, kDBCreator, kDBType);
  268.                 this->SaveAs(saveInFSSpec);
  269.             }
  270.  
  271.             result = this->BuildObjectSpecifier(t);
  272.             break;
  273.         }
  274.         
  275.         case kAEClose:
  276.         {
  277.             //
  278.             // Close can be pretty dangerous if we're multithreaded
  279.             // and some other thread is working with this document.
  280.             // Therefore, we will close this document later.
  281.             //
  282.             this->Save();
  283.             TApplication::Instance()->MarkForClose(this);
  284.             result = this->BuildObjectSpecifier(t);
  285.             break;
  286.         }
  287.         
  288.         default:
  289.         {
  290.             result = Inherited::AECommand(t, aeCommandID, auxObjects, auxInfo);
  291.             break;
  292.         }
  293.     }
  294.     
  295.     return result;
  296. }
  297.  
  298. //--------------------------------------------------------------------------------
  299. // TScriptableDBDocument::CreateNewElement
  300. //--------------------------------------------------------------------------------
  301. TAbstractScriptableObject* TScriptableDBDocument::CreateNewElement(const TAETransaction& t, DescType newObjectClass, TDescriptor initialData, TDescriptor initialProperties, Boolean& usedInitialData, Boolean& usedInitialProperties)
  302. {
  303.     return Inherited::CreateNewElement(t, newObjectClass, initialData, initialProperties, usedInitialData, usedInitialProperties);
  304. }
  305.  
  306. //----------------------------------------------------------------------------------------
  307. // TScriptableDBDocument::RepresentativeScriptingObject
  308. //
  309. // The representative can provide properties for the document.
  310. // All commands identified by SendCommandToRepresentative are also sent to the
  311. // representative
  312. //----------------------------------------------------------------------------------------
  313. TAbstractScriptableObject* TScriptableDBDocument::RepresentativeScriptingObject(const TAETransaction&)
  314.     {
  315.     return new TDBElementToken(this->GetMetaRoot());
  316.     }
  317.  
  318. //----------------------------------------------------------------------------------------
  319. // TScriptableDBDocument::SendCommandToRepresentative
  320. //----------------------------------------------------------------------------------------
  321. Boolean TScriptableDBDocument::SendCommandToRepresentative(const TAETransaction& t, long aeCommandID)
  322.     {
  323.     if((aeCommandID == kAESave) || (aeCommandID == kAEClose))
  324.         return false;
  325.     
  326.     return Inherited::SendCommandToRepresentative(t, aeCommandID);
  327.     } // TScriptableDBDocument::SendCommandToRepresentative
  328.     
  329. //::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
  330. // Methods of TScriptableDBDocument
  331. //::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
  332.  
  333. //--------------------------------------------------------------------------------
  334. // TScriptableDBDocument::SaveAs
  335. //--------------------------------------------------------------------------------
  336. void TScriptableDBDocument::SaveAs(TFSSpecification& fileSpec)
  337. {
  338.     TFSSpecification currentSpecification;
  339.     Boolean hasSpec = this->DocumentFSSpecification(currentSpecification);
  340.     
  341.     //
  342.     // Is the parameter to "Save As" the same as the specification
  343.     // already stored in our backing-store object?  If so, just
  344.     // save, and don't mess with save-as.
  345.     //
  346.     if(hasSpec && (currentSpecification == fileSpec))
  347.     {
  348.         this->Save();
  349.     }
  350.     else
  351.     {
  352.         //
  353.         // Create a backing store object to save the database into
  354.         // and call SetBackingStore to set up and save the file.
  355.         //
  356.         // ◊Question:    If we already have a backing-store object,
  357.         //                should we delete its file?
  358.         //
  359.         THFSBackingStore* backingStore = new THFSBackingStore(fileSpec, kDBCreator, kDBType);
  360.         this->SetBackingStore(backingStore);
  361.     }
  362. }
  363.  
  364.